/*
 * Copyright 2025-2026 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package hawk.demo;

import glz.hawkgenerator.java.*;
import glz.hawkgenerator.java.type.*;
import hawk.util.ProjectUtils;

import javax.lang.model.element.Modifier;
import java.lang.annotation.*;

import static glz.hawkgenerator.java.type.PrimitiveTypeName.BOOLEAN;
import static glz.hawkgenerator.java.type.VoidTypeName.VOID;

/**
 * This class is responsible for
 *
 * @author Hawk
 */
public class AnnotationGenerator {
    private final String packageName;

    public AnnotationGenerator(String packageName) {
        this.packageName = packageName;
    }

    public void generateAnnotation() {


        ProjectUtils.write(packageName, InterfaceSpec.builder("ConstraintValidatorContext", Modifier.PUBLIC).build());

        ProjectUtils.write(packageName, InterfaceSpec.builder("Payload", Modifier.PUBLIC).build());


        InterfaceSpec interfaceSpec = InterfaceSpec.builder("ConstraintValidator", Modifier.PUBLIC)
                .addTypeVariable(TypeVariableName.of("A", Annotation.class))
                .addTypeVariable(TypeVariableName.of("T"))
                .addMethod(MethodSpec.builder(VOID, "initialize", Modifier.DEFAULT)
                        .addParameter(TypeVariableName.of("A"), "constraintAnnotation")
                        .build())
                .addMethod(MethodSpec.builder(BOOLEAN, "isValid")
                        .addParameter(TypeVariableName.of("T"), "value")
                        .addParameter(ClassName.of(packageName, "ConstraintValidatorContext"), "context")
                        .build())
                .build();
        ProjectUtils.write(packageName, interfaceSpec);

        AnnotationSpec annotationSpec1 = AnnotationSpec.builder("Constraint", Modifier.PUBLIC)
                .addAnnotation(AnnotationInstanceSpec.builder(Documented.class).build())
                .addAnnotation(AnnotationInstanceSpec.builder(Target.class)
                        .addMember("value", new ElementType[]{ElementType.ANNOTATION_TYPE})
                        .build())
                .addAnnotation(AnnotationInstanceSpec.builder(Retention.class)
                        .addMember("value", RetentionPolicy.RUNTIME)
                        .build())
                .addAttributes(AttributeSpec.builder(ArrayTypeName.ofClass(Class.class), "validatedBy").defaultValue("{}").build())
                .build();
        ProjectUtils.write(packageName, annotationSpec1);

        AnnotationSpec annotationSpec = AnnotationSpec.builder("NotBlank", Modifier.PUBLIC)
                .addAttribute(AttributeSpec.builder(String.class, "message").defaultValue("$S", "{javax.validation.constraints.NotBlank.message}").build())
                .addAttribute(AttributeSpec.builder(ArrayTypeName.ofTypeName(ParameterizedTypeName.of(Class.class, WildcardTypeName.of())), "groups").defaultValue("{}").build())
                .addAttributes(AttributeSpec.builder(ArrayTypeName.ofTypeName(ParameterizedTypeName.of(Class.class, WildcardTypeName.ofUpper(ClassName.of(packageName, "Payload")))), "payload").defaultValue("{}").build())
                .addAnnotation(AnnotationInstanceSpec.builder(Documented.class).build())
                .addAnnotation(AnnotationInstanceSpec.builder(Retention.class)
                        .addMember("value", RetentionPolicy.RUNTIME)
                        .build())
                .addAnnotation(AnnotationInstanceSpec.builder(Target.class)
                        .addMember("value", new ElementType[]{ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
                        .build())
                .addAnnotation(AnnotationInstanceSpec.builder(Repeatable.class)
                        .addMember("value", ClassName.of(packageName, "NotBlank", "List"))
                        .build())
                .addAnnotation(AnnotationInstanceSpec.builder(ClassName.of(packageName, "Constraint"))
                        .addMember("validatedBy", new Object[0])
                        .build())
                .addInnerType(AnnotationSpec.builder("List", Modifier.PUBLIC)
                        .addAnnotation(AnnotationInstanceSpec.builder(Documented.class).build())
                        .addAnnotation(AnnotationInstanceSpec.builder(Retention.class)
                                .addMember("value", RetentionPolicy.RUNTIME)
                                .build())
                        .addAnnotation(AnnotationInstanceSpec.builder(Target.class)
                                .addMember("value", new ElementType[]{ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
                                .build())
                        .addAttribute(AttributeSpec.builder(ArrayTypeName.ofTypeName(ClassName.of(packageName, "NotBlank")), "value").build())
                        .build())
                .build();
        ProjectUtils.write(packageName, annotationSpec);
    }
}
